#ifndef __LINE__H
#define __LINE__H
#include "Point.h"

template <class T>
class Line
{
public:
	friend class Iterator;
	class Iterator {
		friend class Line;
	private:
		/** @note public creation is done via Begin() */
		void Init(const Line *pLine) 
		{
			m_ptCurrent = pLine->m_p1;
			m_nXDelta = pLine->m_p2.Col() - pLine->m_p1.Col();
			m_nYDelta = pLine->m_p2.Row() - pLine->m_p1.Row();
			m_nAccumulator = 0; 
			m_nRemaining = abs(m_nYDelta) > abs(m_nXDelta) ? abs(m_nYDelta) : abs(m_nXDelta);
		} 
	public:
		Point<S32> GetPoint() { return m_ptCurrent; }
		void Next()
		{
			if (!m_nRemaining--) 
				return;
			S32 nRowInc = m_nYDelta > 0 ? +1 : -1;
			S32 nColInc = m_nXDelta > 0 ? +1 : -1;
			if (abs(m_nXDelta) > abs(m_nYDelta)) {
				m_nAccumulator += abs(m_nYDelta);
				if (m_nAccumulator > abs(m_nXDelta)) {
					m_ptCurrent.Move(nRowInc, nColInc);
					m_nAccumulator -= abs(m_nXDelta);
				} else 
					m_ptCurrent.Move(0, nColInc);
			} else {
				m_nAccumulator += abs(m_nXDelta);
				if (m_nAccumulator > abs(m_nXDelta)) {
					m_ptCurrent.Move(nRowInc, nColInc);
					m_nAccumulator -= abs(m_nYDelta);
				} else 
					m_ptCurrent.Move(nRowInc, 0);
			}
		}
		bool End() { return !m_nRemaining; }
		~Iterator() {};
	private:
		Point<T> m_ptCurrent;
		T m_nXDelta;
		T m_nYDelta;
		/** The accumulator is increased to let us know
		 *  when we need to change the coordinate with the smaller delta
		 */
		T m_nAccumulator; 
		/** Remaining number of steps */
		T m_nRemaining;
	};
	
	Line(T nRow1, T nCol1, T nRow2, T nCol2) : m_p1(nRow1, nCol1), m_p2(nRow2, nCol2) {}
	void Begin(Iterator *pIter) { pIter->Init(this); } 
private:
	Point<T> m_p1, m_p2;
};
#endif//__LINE__H
